home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C011.ZIP / PC_COM.ASM < prev    next >
Assembly Source File  |  1990-01-19  |  14KB  |  423 lines

  1. title IBM PC Communications I/O Routines -- Curt Klinsing
  2. pgroup  group   prog
  3. prog segment byte public 'prog'
  4. ;
  5. ;A set  of Lattice C callable functions to support
  6. ;interrupt driven character I/O on the  IBM PC. Input
  7. ;is buffered, output is polled.
  8. ;
  9. public  init_comm       ;initialize the comm port,
  10. public  uninit_comm     ;remove initialization,
  11. public  set_xoff                ;enable/disable XON/XOFF,
  12. public  get_xoff                ;read XON/XOFF state,
  13. public  rcvd_xoff       ;returns true if XOFF rcvd,
  14. public  sent_xoff       ;true if XOFF sent,
  15. public  inp_cnt         ;returns count of rcv chars,
  16. public  inp_char                ;get one char from buffer,
  17. public  inp_flush       ;flush input buffer,
  18. public  outp_char       ;output a character,
  19. ;
  20. ;A better description can be found in the comment
  21. ;block  in each function.
  22. ;
  23.         assume  cs:pgroup
  24.  
  25. ;
  26. FALSE   EQU     0
  27. TRUE    EQU     NOT FALSE
  28. ;
  29. BASE    EQU     03F8H   ;BASE FOR SERIAL BOARD
  30. ;
  31. LCR     equ     BASE+3  ; Line control register
  32. IER     equ     BASE+1  ; Interrup Enable Register
  33. MCR     EQU     BASE+4  ;modem control register
  34. EnblDRdy equ    01H     ; enable 'data-ready' interrupt bit
  35. IntCtlr  EQU    21H     ;OCW 1 FOR 8259 CONTROLLER
  36. EnblIRQ4 EQU    0EFH    ;Enable COMMUNICATIONS (IRQ4)
  37. DATAPORT EQU    BASE    ;transmit/receive data port
  38. MaskIRQ4 EQU    10H     ;BIT TO DISABLE COMM INTERRUPT (IRQ4)
  39.  
  40. MDMSTA  EQU     BASE+5  ;line status register
  41. MDMMSR  EQU     BASE+6  ;modem status register
  42. MDMBAD  EQU     BASE    ;lsb baud resgister
  43. MDMBD1  EQU     BASE+1  ;msb baud rate register
  44. MDMCD   EQU     80H     ;mask for carrier dectect
  45. SETBAU  EQU     80H     ;code for Divisor Latch Access Bit
  46. MDMTBE  EQU     20H     ;8250 tbe flag
  47. MDMBRK  EQU     40H     ;command code for 8250 break
  48. LINMOD  EQU     03H     ;line mode=8 bit, no parity
  49. MDMMOD  EQU     0BH     ;modem mode = DTR and RTS HIGH
  50. STOP2   EQU     04H     ;BIT FOR TWO STOP BITS IF BAUD<300
  51. RS8259  EQU     20H     ;OCW 3 FOR 8259
  52. RSTINT  EQU     64H     ;SPECIFIC EOI FOR COMM INTERRUPT 
  53. XOFF    EQU     13H     ;XOFF character
  54. XON     EQU     11H     ;XON character
  55. ;
  56. ;       MISCELLANEOUS EQUATES
  57. ;
  58. CR      EQU     13
  59. LF      EQU     10
  60. DosCall EQU     33      ;INTERRUPT NUMBER FOR DOS CALL  
  61. CNSTAT  EQU     11      ;FUNCTION NUMBER FOR CONSOLE STATUS
  62. CNIN    EQU     1       ;FUNCTION NUMBER FOR CONSOLE INPUT
  63. BUFSIZ  EQU     512     ;Max NUMBER OF CHARS
  64. SetIntVect  EQU 25H     ;SET INTERRUPT VECTOR FUNCTION NUMBER
  65.  
  66. ;
  67. ;       DUMP BUFFER, COUNT AND POINTER.  
  68. ;
  69. CIRC_BUF DB     BUFSIZ DUP(?)   ;ALLOW 512 MaxIMUM BUFFERED CHARACTERS
  70. BUF_TOP EQU     $ - 1           ;KEEP TRACK OF THE TOP OF THE BUFFER
  71. CIRC_TOP DW     BUF_TOP         ;
  72. ;
  73. CIRC_IN DW      OFFSET CIRC_BUF ;POINTER TO LAST CHAR. PLACED IN BUFFER
  74. CIRC_CUR DW     OFFSET CIRC_BUF ;POINTER TO NEXT CHAR. TO BE RETRIEVED FROM
  75.                                 ; BUFFER
  76. CIRC_CT DW      0               ;COUNT OF CHARACTERS USED IN BUFFER
  77. SNT_XOFF DB     FALSE           ;FLAG TO CHECK IF AN XOFF HAS BEEN SEND
  78. GOT_XOFF  DB    FALSE           ;FLAG TO CHECK IF AN XOFF HAS BEEN RECEIVED
  79. SEE_XOFF  DB    FALSE           ;FLAT TO SEE IF WE ARE INTERESTED IN XON/XOFF
  80. ;
  81. ;
  82. ;
  83. ;set_xoff(flag)         Enable (flag != 0) or disable
  84. ;int flag;              (flag == 0) XON/ XOFF protocol
  85. ;                       for the character input stream.
  86. ;If enabled, an XOFF will be sent when  the buffer
  87. ;reaches 3/4 full. NOTE: an XON will not be sent auto-
  88. ;matically. Your program must do it when it sees
  89. ;the rcvd_xoff() flag,  and ready for more chars.
  90. ;
  91. set_xoff proc near
  92.         push    bp
  93.         PUSH    DS              ;SAVE DATA SEGMENT
  94.         mov     bx,[bp+6]       
  95.         push    cs
  96.         pop     ds              ; move code seg addr to data seg reg.
  97.         cmp     bx,0
  98.         jnz     to_on
  99.         mov     see_xoff,FALSE
  100.         jmp     done1
  101. to_on:  mov     see_xoff,TRUE
  102. done1:  pop     ds
  103.         pop     bp
  104.         ret
  105. set_xoff endp
  106. ;
  107. ;flag=  get_xoff()      Returns the current setting
  108. ;                       of the XON/ XOFF flag set
  109. ;by set_xoff(), above.
  110. ;
  111. get_xoff proc near
  112.         push    bp
  113.         push    ds              ; save data reg
  114.         push    cs
  115.         pop     ds              ; move code seg addr to data seg reg.
  116.         xor     ax,ax
  117.         mov     al,see_xoff
  118.         pop     ds
  119.         pop     bp
  120.         ret
  121. get_xoff endp
  122. ;
  123. ;flag=  sent_xoff();    Returns true if an XOFF
  124. ;                       character was sent, indicating
  125. ;the receive buffer is  3/4 full.
  126. ;
  127. sent_xoff proc  near
  128.         push    bp
  129.         push    ds              ; save data reg
  130.         push    cs
  131.         pop     ds              ; move code seg addr to data seg reg.
  132.         xor     ax,ax
  133.         mov     al,snt_xoff
  134.         pop     ds
  135.         pop     bp
  136.         ret
  137. sent_xoff endp
  138. ;
  139. ;rcvd_xoff()            Returns true if an XOFF was
  140. ;                       received; will return false as
  141. ;soon as an XON is received. Does not effect data output,
  142. ;only indicates the above. (Obviously useless for binary
  143. ;data.)
  144. ;
  145. rcvd_xoff proc  near
  146.         push    bp
  147.         push    ds              ; save data reg
  148.         push    cs
  149.         pop     ds              ; move code seg addr to data seg reg.
  150.         xor     ax,ax
  151.         mov     al,got_xoff
  152.         pop     ds              ; restore data reg
  153.         pop     bp
  154.         ret
  155. rcvd_xoff endp
  156. ;
  157. ;count= inp_cnt()       Returns the number of characters
  158. ;                       available in the input buffer.
  159. ;
  160.  
  161. inp_cnt proc near       
  162.         push    bp
  163.         push    ds              ; save data segment
  164.         push    cs
  165.         pop     ds              ; move code seg addr to data seg reg
  166.         mov     ax,circ_ct
  167.         pop     ds
  168.         pop     bp
  169.         ret
  170. inp_cnt endp
  171. ;
  172. ;inp_flush()    Flush the input buffer.
  173. ;
  174. inp_flush proc  near    
  175.         push    bp
  176.         push    ds              ; save data reg
  177.         push    cs
  178.         pop     ds              ; move code seg addr to data seg reg.
  179.         mov     bx,offset circ_buf
  180.         mov     circ_in,bx      
  181.         mov     circ_cur,bx
  182.         xor     ax,ax
  183.         mov     circ_ct,ax
  184.         pop     ds
  185.         pop     bp
  186.         ret
  187. inp_flush endp
  188.  
  189. ; --------- Init -----------------------------------
  190. ; Program initialization:
  191. ;   --  Set up vector for RS232 interrupt (0CH)
  192. ;   --  Enbl IRQ4
  193. ;   --  Enbl RS232 interrupt on data ready
  194. ;
  195. ; ---------------------------------------------------
  196.  
  197. init_comm proc  near
  198.         push    bp
  199.         cli
  200.  
  201. ;  ---- Set up  INT x'0C' for IRQ4
  202.  
  203.         push    ds
  204.         push    cs
  205.         pop     ds              ;cs to ds
  206.         mov     dx,offset IntHdlr ;relative adddres of interrupt handler
  207.         mov     al,0cH          ;interrupt number for comm.
  208.         mov     ah,SetIntVect   ;function number for setting int vector
  209.         int     DosCall         ;set interrupt in 8086 table
  210.         pop     ds              ;restore DS
  211.  
  212. ;  ---- Enbl IRQ4 on 8259 interrupt controller
  213.  
  214.         cli
  215.  
  216.         in      al,IntCtlr      ; get current masks 
  217.         and     al,EnblIRQ4     ; Reset IRQ4 mask
  218.         out     IntCtlr,al      ; And restore to IMR
  219.  
  220. ;  ---   Enbl 8250 data ready interrupt
  221.  
  222.         mov     dx,LCR          ; DX ==> LCR
  223.         in      al,dx           ; Reset DLAB for IER access
  224.         and     al,7FH
  225.         out     dx,al
  226.         mov     dx,IER          ; Interrupt Enbl Register
  227.         mov     al,EnblDRdy     ; Enable 'data-ready' interrupt
  228.         out     dx,al
  229.  
  230. ;  ---   Enbl OUT2 on 8250
  231.  
  232.         mov     dx,MCR          ; modem control register        
  233.         mov     al,08H          ; Enable OUT2
  234.         out     dx,al
  235.  
  236.         sti
  237.  
  238.         pop     bp
  239.         ret
  240. init_comm endp
  241. ;
  242. ;uninit_comm()          Removes the interrupt structure
  243. ;                       installed by init_comm(). Must be
  244. ;done before passing control to the DOS, else chars received
  245. ;will be stored into the next program loaded!
  246. ;
  247. uninit_comm proc near
  248.         push    bp
  249. ; ---   Disable IRQ4 on 8259
  250.  
  251.         cli
  252.         in      al,IntCtlr      ;GET OCW1 FROM 8259
  253.         or      al,MaskIRQ4     ;DISABLE COMMUNICATIONS INTERRUPT
  254.         out     IntCtlr,al
  255.  
  256. ; ---   Disable 8250 data ready interrupt
  257.         
  258.         mov     dx,LCR          ; DX ==> LCR
  259.         in      al,dx           ; Reset DLAB for IER access
  260.         and     al,7FH
  261.         out     dx,al
  262.         mov     dx,IER          ; Interrupt Enbl Register
  263.         mov     al,0            ; Disable all 8250 interrupts
  264.         out     dx,al
  265.  
  266. ;  ---   Disable OUT2 on 8250
  267.  
  268.         mov     dx,MCR          ; modem control register        
  269.         mov     al,0            ; Disable OUT2
  270.         out     dx,al
  271.  
  272.         sti
  273.                 pop     bp
  274.         ret
  275. uninit_comm endp
  276. ;
  277. ;char inp_char()        Return a character from the input
  278. ;                       buffer. Assumes you have called
  279. ;inp_cnt() to see if theres any characters to get.
  280. ;
  281. inp_char proc near      
  282.         push    bp
  283.         push    ds              ; save data reg
  284.         push    cs
  285.         pop     ds              ; move code seg addr to data seg reg.
  286.         mov     bx,circ_cur
  287.         xor     ax,ax
  288.         mov     al,[bx]         ;get next char from circ_buf
  289.         DEC     circ_ct         ;decrement circ_buf COUNT
  290.         CMP     bx,circ_top     ;ARE WE AT THE TOP OF THE circ_buf?
  291.         JZ      reset_cur       ;JUMP IF SO
  292.         INC     bx              ;ELSE, BUMP PTR
  293.         JMP SHORT upd_cur
  294. reset_cur:
  295.         mov     bx,OFFSET circ_buf      ;RESET circ_in TO BOTTOM OF BUF.
  296. upd_cur:
  297.         mov     circ_cur,bx             ;SAVE NEW PTR
  298.         xor     cx,cx
  299.         mov     cl,see_xoff     ;check if interested in xon/xoff
  300.         cmp     cl,TRUE
  301.         jnz     clnup2          ;not interested, so goto return
  302.         cmp     snt_xoff,TRUE   ;have we sent an xoff?
  303.         jnz     clnup2          ;no, so return
  304.         cmp     circ_ct,80h     ;yes, so see in buf is now emptying
  305.         jg      clnup2          ;not empty enuf to send xon, jump to ret
  306.         mov     snt_xoff,FALSE
  307.         mov     cl,XON
  308.         push    ax              ; save char
  309.         call    comout
  310.         pop     ax
  311. clnup2: pop     DS              ;GET BACK ENTERING DS
  312.         pop     bp
  313.         ret
  314. inp_char endp
  315. ;
  316. ;outp_char(c)           Output the character to the
  317. ;char c;                serial port. This is not buffered
  318. ;                       or interrupt driven.
  319. ;
  320. outp_char proc  near
  321.         push    bp
  322.         mov     bp,sp
  323.         mov     cl,[bp+4]
  324.         sti
  325.         call    comout
  326.         pop     bp
  327.         ret
  328. outp_char endp
  329. ;
  330. ;Local  subroutine: output CL to the port.
  331. ;
  332. comout: mov     dx,MDMSTA       
  333.         in      al,dx           ; get 8250 status
  334.         and     al,MDMTBE       ; check for transmitter ready
  335.         jz      comout          ; jump if not to wait
  336.         mov     al,cl           ; get char to al
  337.         mov     dx,DATAPORT     
  338.         out     dx,al           ; output char to 8251
  339.         ret
  340. ;
  341. ;       RECEIVE INTERRUPT HANDLER (CHANGED TO PLACE CHARACTERS IN A
  342. ;        CIRCULAR circ_buf AND TO SEND AN XOFF IF THE circ_buf IS MORE THAN
  343. ;        3/4 FULL - S.G.)
  344. ;
  345. IntHdlr:
  346.         CLI
  347.         push    cx
  348.         push    dx
  349.         push    bx
  350.         push    ax
  351.         push    ds
  352.         mov     ax,cs           ;get cur code segment
  353.         mov     ds,ax           ; and set it as data segment
  354.         mov     bx,circ_in      ;GET circ_buf IN PTR
  355.         mov     DX,DATAPORT     ;GET DATA PORT NUMBER
  356.         IN      AL,DX           ;GET RECEIVED CHARACTER
  357. ;       push    ax
  358. ;       push    dx   
  359. ;       xor     ax,ax
  360. ;       xor     dx,dx
  361. ;       mov     dl,al
  362. ;       mov     ah,2
  363. ;       int     DosCall
  364. ;       pop     dx
  365. ;       pop     ax
  366.         xor     cx,cx
  367.         mov     cl,see_xoff     ;check if interested in xon/xoff
  368.         cmp     cl,TRUE
  369.         jnz     ck_full         ;not interested goto ck if buf full
  370.         mov     cl,al           ;put char in cl for testing
  371.         and     cl,7fh          ;turn off any parity bits 
  372.         cmp     cl,XOFF         ;see if we got an xoff
  373.         jnz     ck_xon
  374.         mov     got_Xoff,TRUE   ; code for handling xon/xoff from remote
  375.         jmp     clnup
  376. ck_xon: cmp     cl,XON
  377.         jnz     reg_ch
  378.         mov     got_Xoff,FALSE
  379.         jmp     clnup
  380. ;
  381. ;Normal character; not  XON/XOFF, or XON/XOFF disabled.
  382. ;
  383. reg_ch: test    snt_Xoff,TRUE   ;SEE IF sentXoff IS SET
  384.         jnz     ck_full         ;IF SO, DON'T SEND ANOTHER XOFF
  385.         CMP     circ_ct,(BUFSIZ * 3)/4  ;ALLOW BUF TO BECOME 3/4 FULL BEFORE
  386.                                         ; SENDING XOFF
  387.         jb      savch           ;IF IT'S OK, CONTINUE
  388.         push    ax              ;SAVE CHARACTER
  389.         mov     CL,XOFF         ;GET XOFF CHARACTER
  390.         mov     snt_Xoff,TRUE  ;RESET sentXoff
  391.         call    comout          ; AND SEND IT
  392.         pop     ax              ;RETRIEVE CHARACTER
  393.         JMP SHORT savch         ;IF WE'RE HERE, THE circ_buf HAS BUFSIZ-80H
  394.                                 ;  CHARACTERS
  395. ck_full:
  396.         CMP     circ_ct,BUFSIZ  ;SEE IF circ_buf ALREADY FULL
  397.         JZ      clnup           ; JUMP IF SO, DO NOT PLACE CHARACTER IN BFR
  398. savch:                          
  399.         mov     [bx],AL         ;SAVE NEW CHARACTER IN circ_buf
  400.         inc     circ_ct         ;BUMP circ_buf COUNT
  401.         CMP     bx,circ_top     ;ARE WE AT THE TOP OF THE circ_buf?
  402.         JZ      reset_in        ;JUMP IF SO
  403.         inc     bx              ;ELSE, BUMP PTR
  404.         JMP SHORT into_buf
  405. reset_in:
  406.         mov     bx,OFFSET circ_buf      ;RESET circ_in TO BOTTOM OF BUF.
  407. into_buf:
  408.         mov     circ_in,bx              ;SAVE NEW PTR
  409. clnup:
  410.         mov     AL,RSTINT
  411.         OUT     RS8259,AL       ;ISSUE SPECIFIC EOI FOR 8259
  412.         pop     ds              ;GET BACK ENTERING DS
  413.         pop     ax
  414.         pop     bx
  415.         pop     dx
  416.         pop     cx
  417.         sti
  418.         iret
  419. ;
  420. prog    ends
  421.  
  422. end
  423.